package com.cskaoyan.service.wx.impl;

import com.cskaoyan.bean.*;
import com.cskaoyan.bean.param.CommonData;
import com.cskaoyan.bean.vo.coupon.CouponUserVO;
import com.cskaoyan.mapper.MarketCartMapper;
import com.cskaoyan.mapper.MarketCouponMapper;
import com.cskaoyan.mapper.MarketCouponUserMapper;
import com.cskaoyan.mapper.MarketGoodsMapper;
import com.cskaoyan.service.wx.WXCouponService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Service
@Transactional
public class WXCouponServiceImpl implements WXCouponService {

    @Autowired
    MarketCouponMapper marketCouponMapper;

    @Autowired
    MarketCouponUserMapper marketCouponUserMapper;

    @Autowired
    MarketCartMapper marketCartMapper;

    @Autowired
    MarketGoodsMapper marketGoodsMapper;

    @Override
    public int receive(Integer couponId) {
        // 这里获得的已经是限定type、status、deleted都为0的优惠券，但要考虑并发问题
        // 1.首先查询优惠券的信息
        MarketCouponExample marketCouponExample = new MarketCouponExample();
        MarketCouponExample.Criteria criteria = marketCouponExample.createCriteria();
        // 查找未被删除的
        criteria.andDeletedEqualTo(false).andIdEqualTo(couponId);
        List<MarketCoupon> marketCouponList = marketCouponMapper.selectByExample(marketCouponExample);
        // 说明该优惠券已被删除
        if (marketCouponList.size() == 0) {
            return 10000;
        }
        // 没被删除，则可获取对象
        MarketCoupon marketCoupon = marketCouponList.get(0);
        // 2.判断是否是可领取类型
        if (marketCoupon.getType() != 0) {
            return -10000;
        }
        return judgeCoupon(couponId, marketCouponExample, marketCoupon);
    }

    // 领取和兑换共用的判断优惠券有效性的方法
    private int judgeCoupon(Integer couponId, MarketCouponExample marketCouponExample, MarketCoupon marketCoupon) {
        // 3.判断优惠券是否下架，此时状态码为2，不需要再更新了
        if (marketCoupon.getStatus() == 2) {
            return 300;
        }
        // 4.手动判断优惠券是否过期（此时状态码为0），过期则更新优惠券表(这里比较特殊)
        // 只需要判断绝对天数的情况
        if (marketCoupon.getTimeType() == 1) {
            Date endTime = marketCoupon.getEndTime();
            if (endTime != null) {
                // 结束时间早于当前时间，已过期
                if (endTime.compareTo(new Date()) < 0) {
                    // 只要修改优惠券表
                    marketCoupon.setStatus((short) 1);
                    marketCoupon.setUpdateTime(new Date());
                    int update = marketCouponMapper.updateByExampleSelective(marketCoupon, marketCouponExample);
                    return 2000;
                }
            }
        }
        // 获取当前用户信息
        Subject subject = SecurityUtils.getSubject();
        MarketUser primaryPrincipal = (MarketUser) subject.getPrincipals().getPrimaryPrincipal();

        MarketCouponUserExample marketCouponUserExample = new MarketCouponUserExample();
        // 5.判断持有该优惠券数量是否超过限制
        Short limit = marketCoupon.getLimit();
        // limit为0表示不限制领取数量,不需要判断是否超过上限
        if (limit != 0) {
            // 查询用户已持有该优惠券的数量
            // 条件为优惠券id和用户id,以及未被删除
            marketCouponUserExample.createCriteria().andDeletedEqualTo(false).
                    andCouponIdEqualTo(couponId).andUserIdEqualTo(primaryPrincipal.getId());
            List<MarketCouponUser> marketCouponUserList = marketCouponUserMapper.selectByExample(marketCouponUserExample);
            if (marketCouponUserList.size() >= limit) {
                return 40;
            }
        }
        // 6.判断发行数量
        Integer total = marketCoupon.getTotal();
        // total为0表示不限量，不需要判断
        if (total != 0) {
            // 判断user表中持有该优惠券的数量
            marketCouponUserExample.createCriteria().andDeletedEqualTo(false).
                    andCouponIdEqualTo(couponId);
            List<MarketCouponUser> marketCouponUserList = marketCouponUserMapper.selectByExample(marketCouponUserExample);
            if (marketCouponUserList.size() >= total) {
                return 5;
            }
        }
        // todo 存入coupon_user表
        MarketCouponUser marketCouponUser = new MarketCouponUser();
        marketCouponUser.setUserId(primaryPrincipal.getId());
        marketCouponUser.setCouponId(couponId);
        // marketCouponUser.setStatus((short) 0);
        // 分情况
        if (marketCoupon.getTimeType() == 0) {
            // 相对天数
            marketCouponUser.setStartTime(new Date());

            Short days = marketCoupon.getDays();
            Date endDate = new Date(System.currentTimeMillis() + days * 24 * 60 * 60 * 1000);
            marketCouponUser.setEndTime(endDate);
        } else {
            // 绝对天数
            marketCouponUser.setStartTime(marketCoupon.getStartTime());
            marketCouponUser.setEndTime(marketCoupon.getEndTime());
        }
        marketCouponUser.setAddTime(new Date());
        marketCouponUser.setUpdateTime(new Date());

        return marketCouponUserMapper.insertSelective(marketCouponUser);
    }

    /**
     * 个人主页优惠券选项兑换优惠券
     *
     * @return {"errno":0,"errmsg":"成功"}，{"errno":742,"errmsg":"优惠券不正确"}
     * @Param {code: "someCode"}
     */
    @Override
    public int exchange(String code) {
        // 这里获得的已经是限定type、status、deleted都为0的优惠券，但要考虑并发问题
        // 1.首先查询优惠券的信息
        MarketCouponExample marketCouponExample = new MarketCouponExample();
        MarketCouponExample.Criteria criteria = marketCouponExample.createCriteria();
        // 查找未被删除的
        criteria.andDeletedEqualTo(false).andCodeEqualTo(code);
        List<MarketCoupon> marketCouponList = marketCouponMapper.selectByExample(marketCouponExample);
        // 说明该优惠券已被删除
        if (marketCouponList.size() == 0) {
            return 10000;
        }
        // 没被删除，则可获取对象
        MarketCoupon marketCoupon = marketCouponList.get(0);
        // 2.判断是否是可领取类型
        if (marketCoupon.getType() != 2) {
            return -10000;
        }
        // 后面可以复用
        return judgeCoupon(marketCoupon.getId(), marketCouponExample, marketCoupon);
    }

    /**
     * 个人主页优惠券选项显示优惠券
     * ?status=1&page=1&limit=10
     * 需要VO手摇车
     *
     * @return CommonData
     */
    @Override
    public CommonData<CouponUserVO> mylist(Short status, BasePageInfo basePageInfo) {
        PageHelper.startPage(basePageInfo.getPage(), basePageInfo.getLimit());

        // todo
        List<CouponUserVO> couponUserVOS = getCouponUserVOS(status);
        // 获取用户id
        Subject subject = SecurityUtils.getSubject();
        MarketUser primaryPrincipal = (MarketUser) subject.getPrincipals().getPrimaryPrincipal();
        Integer userId = primaryPrincipal.getId();

        MarketCouponUserExample marketCouponUserExample = new MarketCouponUserExample();
        MarketCouponUserExample.Criteria criteria = marketCouponUserExample.createCriteria();

        criteria.andDeletedEqualTo(false).andStatusEqualTo(status).andUserIdEqualTo(userId);
        List<MarketCouponUser> marketCouponUserList = marketCouponUserMapper.selectByExample(marketCouponUserExample);

        PageInfo<MarketCouponUser> marketCouponUserPageInfo = new PageInfo<>(marketCouponUserList);
        PageInfo<CouponUserVO> couponUserVOPageInfo = new PageInfo<>(couponUserVOS);
        couponUserVOPageInfo.setTotal(marketCouponUserPageInfo.getTotal());
        couponUserVOPageInfo.setPages(marketCouponUserPageInfo.getPages());
        return CommonData.data(couponUserVOPageInfo);
    }

    /**
     * cartId为0时需要靠userId, checked=1, deleted=0来确定商品
     * 需要手摇车, 可以把所有可用的优惠券都查出来，再根据需求设置available，limit和total相同
     *
     * @param cartId
     */
    @Override
    public CommonData<CouponUserVO> selectlist(Integer cartId) {
        // todo 先获取该用户所有可用的优惠券
        List<CouponUserVO> couponUserVOList = getCouponUserVOS((short) 0);
        // 如果没有可用的,直接返回
        if (couponUserVOList.size() == 0) {
            PageInfo<CouponUserVO> couponUserVOPageInfo = new PageInfo<>(couponUserVOList);
            return CommonData.data(couponUserVOPageInfo);
        }
        // 将所有涉及的优惠券取出
        HashSet<Integer> couponIdSet = new HashSet<>();
        for (CouponUserVO couponUserVO : couponUserVOList) {
            Integer cid = couponUserVO.getCid();
            couponIdSet.add(cid);
        }
        Integer[] integers = new Integer[couponIdSet.size()];
        Integer[] couponIdArray = couponIdSet.toArray(integers);
        // 获取优惠券id的list
        List<Integer> couponIdList = Arrays.asList(couponIdArray);

        MarketCouponExample marketCouponExample = new MarketCouponExample();
        MarketCouponExample.Criteria criteria = marketCouponExample.createCriteria();
        criteria.andStatusEqualTo((short) 0).andIdIn(couponIdList);

        List<MarketCoupon> marketCouponList = marketCouponMapper.selectByExample(marketCouponExample);

        // 获取商品类目及具体商品,以及金额
        HashSet<Integer> categoryIdSet = new HashSet<>();
        HashSet<Integer> goodsIdSet = new HashSet<>();
        BigDecimal totalPrice = new BigDecimal("0");

        if (cartId != 0) {
            // 获取商品id
            MarketCartExample marketCartExample = new MarketCartExample();
            MarketCartExample.Criteria marketCartExampleCriteria = marketCartExample.createCriteria();
            marketCartExampleCriteria.andDeletedEqualTo(false).andIdEqualTo(cartId);
            List<MarketCart> marketCarts = marketCartMapper.selectByExample(marketCartExample);
            if (marketCarts.size() == 1) {
                MarketCart marketCart = marketCarts.get(0);
                // 添加总金额
                BigDecimal price = marketCart.getPrice();
                Short number = marketCart.getNumber();
                BigDecimal multiplyPrice = price.multiply(new BigDecimal(number));
                totalPrice = totalPrice.add(multiplyPrice);

                Integer goodsId = marketCart.getGoodsId();
                goodsIdSet.add(goodsId);
                // 根据goodsId获得类目id
                MarketGoodsExample marketGoodsExample = new MarketGoodsExample();
                MarketGoodsExample.Criteria goodsExampleCriteria = marketGoodsExample.createCriteria();
                goodsExampleCriteria.andDeletedEqualTo(false).andIdEqualTo(goodsId);
                List<MarketGoods> marketGoods = marketGoodsMapper.selectByExampleWithBLOBs(marketGoodsExample);
                // 获取类目id
                if (marketGoods.size() == 1) {
                    MarketGoods goods = marketGoods.get(0);
                    categoryIdSet.add(goods.getCategoryId());
                }
            }
        }
        if (cartId == 0) {
            Subject subject = SecurityUtils.getSubject();
            MarketUser primaryPrincipal = (MarketUser) subject.getPrincipals().getPrimaryPrincipal();
            Integer userId = primaryPrincipal.getId();

            MarketCartExample marketCartExample = new MarketCartExample();
            MarketCartExample.Criteria cartExampleCriteria = marketCartExample.createCriteria();
            // 靠userId, checked=1, deleted=0来确定cart
            cartExampleCriteria.andDeletedEqualTo(false).andCheckedEqualTo(true).andUserIdEqualTo(userId);
            List<MarketCart> marketCarts = marketCartMapper.selectByExample(marketCartExample);
            // 获取商品id,同时获取list
            ArrayList<Integer> goodsIdList = new ArrayList<>();
            for (MarketCart marketCart : marketCarts) {
                Integer goodsId = marketCart.getGoodsId();
                // todo 添加金额
                BigDecimal price = marketCart.getPrice();
                Short number = marketCart.getNumber();
                BigDecimal multiplyPrice = price.multiply(new BigDecimal(number));
                totalPrice = totalPrice.add(multiplyPrice);
                goodsIdSet.add(goodsId);
                goodsIdList.add(goodsId);
            }
            MarketGoodsExample marketGoodsExample = new MarketGoodsExample();
            MarketGoodsExample.Criteria goodsExampleCriteria = marketGoodsExample.createCriteria();
            goodsExampleCriteria.andDeletedEqualTo(false).andIdIn(goodsIdList);
            List<MarketGoods> marketGoods = marketGoodsMapper.selectByExampleWithBLOBs(marketGoodsExample);
            // 获取类目id
            for (MarketGoods marketGood : marketGoods) {
                categoryIdSet.add(marketGood.getCategoryId());
            }
        }

        for (CouponUserVO couponUserVO : couponUserVOList) {
            for (MarketCoupon marketCoupon : marketCouponList) {
                if (couponUserVO.getCid().equals(marketCoupon.getId())) {
                    // 初始为false
                    couponUserVO.setAvailable(false);
                    // 不限商品
                    if (marketCoupon.getGoodsType() == 0) {
                        couponUserVO.setAvailable(true);
                    }
                    // 限制类目
                    if (marketCoupon.getGoodsType() == 1) {
                        Integer[] categoryIdArray = marketCoupon.getGoodsValue();
                        // a: for (Integer categoryId : categoryIdSet) {
                        for (Integer couponCategoryId : categoryIdArray) {
                            if (categoryIdSet.contains(couponCategoryId)) {
                                couponUserVO.setAvailable(true);
                                break;
                            }
                        }
                        // }
                    }
                    // 限制商品
                    if (marketCoupon.getGoodsType() == 2) {
                        Integer[] goodsIdArray = marketCoupon.getGoodsValue();
                        for (Integer couponGoodsId : goodsIdArray) {
                            if (goodsIdSet.contains(couponGoodsId)) {
                                couponUserVO.setAvailable(true);
                                break;
                            }
                        }
                    }
                    // todo 判断金钱,status改变
                    if (totalPrice.compareTo(marketCoupon.getMin()) < 0) {
                        // 低于最低消费，置为false
                        couponUserVO.setAvailable(false);
                    }
                }
            }
        }

        PageInfo<CouponUserVO> couponUserVOPageInfo = new PageInfo<>(couponUserVOList);
        CommonData data = CommonData.data(couponUserVOPageInfo);
        data.setLimit(data.getTotal());
        return data;
    }

    private List<CouponUserVO> getCouponUserVOS(Short status) {
        // 获取用户id
        Subject subject = SecurityUtils.getSubject();
        MarketUser primaryPrincipal = (MarketUser) subject.getPrincipals().getPrimaryPrincipal();
        Integer userId = primaryPrincipal.getId();

        MarketCouponUserExample marketCouponUserExample = new MarketCouponUserExample();
        MarketCouponUserExample.Criteria criteria = marketCouponUserExample.createCriteria();

        criteria.andDeletedEqualTo(false).andStatusEqualTo(status).andUserIdEqualTo(userId);
        // 获取优惠券用户表的数据
        List<MarketCouponUser> marketCouponUserList = marketCouponUserMapper.selectByExample(marketCouponUserExample);

        List<CouponUserVO> couponUserVOS = new ArrayList<>();
        // list不为空时不需要执行下面的逻辑
        if (marketCouponUserList.size() != 0) {
            // 获取涉及优惠券的id集合
            HashSet<Integer> couponIds = new HashSet<>();
            for (MarketCouponUser marketCouponUser : marketCouponUserList) {
                couponIds.add(marketCouponUser.getCouponId());
            }
            Integer[] couponIdArray = new Integer[couponIds.size()];
            Integer[] couponIdsArray = couponIds.toArray(couponIdArray);
            List<Integer> couponIdList = Arrays.asList(couponIdsArray);
            // 获取相应优惠券的数据
            MarketCouponExample marketCouponExample = new MarketCouponExample();
            MarketCouponExample.Criteria couponExampleCriteria = marketCouponExample.createCriteria();
            // todo 查询优惠券表时不需要判断是否删除
            couponExampleCriteria.andIdIn(couponIdList);
            // 注意list为空时不能传入
            List<MarketCoupon> marketCouponList = marketCouponMapper.selectByExample(marketCouponExample);

            for (MarketCouponUser couponUser : marketCouponUserList) {
                boolean flag;
                Short couponUserStatus = couponUser.getStatus();
                if (couponUserStatus == 0) {
                    // 判断是否在有效期内
                    // 没到使用时间，flag置为false，但不需要修改数据库
                    Date startTime = couponUser.getStartTime();
                    Date endTime = couponUser.getEndTime();
                    if (startTime != null && startTime.compareTo(new Date()) > 0) {
                        flag = false;
                    } else if (endTime != null && endTime.compareTo(new Date()) < 0) {
                        flag = false;
                        // 更新数据库
                        couponUser.setStatus((short) 2);
                        couponUser.setUpdateTime(new Date());
                        int update = marketCouponUserMapper.updateByPrimaryKeySelective(couponUser);
                        // todo 这里需不需要修改优惠券表
                        // MarketCoupon marketCoupon = new MarketCoupon();
                        // marketCoupon.setId(couponUser.getCouponId());
                        // marketCoupon.setStatus((short) 1);
                        // int selective = marketCouponMapper.updateByPrimaryKeySelective(marketCoupon);
                    } else {
                        flag = true;
                    }
                } else {
                    flag = false;
                }


                for (MarketCoupon marketCoupon : marketCouponList) {
                    // 优惠券下架的情况
                    if (marketCoupon.getStatus() == 2) {
                        flag = false;
                    }
                    if (marketCoupon.getId().equals(couponUser.getCouponId())) {
                        couponUserVOS.add(new CouponUserVO(couponUser.getId(), couponUser.getCouponId(),
                                flag, marketCoupon.getTag(), marketCoupon.getDesc(), marketCoupon.getName(),
                                marketCoupon.getMin(), marketCoupon.getDiscount(), couponUser.getStartTime(),
                                couponUser.getEndTime()));
                        break;
                    }
                }
            }
        }
        return couponUserVOS;
    }
}

